package local

import (
	"database/sql/driver"
	"encoding/json"
	"fmt"
	"strings"
)

/* ------
自定义格式 LocalStr: (json, forms 都可用)
	TODO 之前前端传 null 会报错, 这个示例中不会。原因未知。
	1. 处理前端传 null 或 "" 正确在数据库中存入 NULL。
		(UNIQUE KEY 为重复 NULL 时 mysql 不会认为有重复。)
		(两个字段作组合 uniqueIndex 时, 只要有一个是 NULL 都不会认为有重复。 "" 不行。)
		(unique 设置 default:'', 用 gorm 新增时 传 null 还是会被设置为默认值。)
		(仅存储时(创建、更新)能存成 NULL。Where("code = ?", code) 等筛选 没用。。 )
	2. 和 string 相互转换: LocalStr(str)、string(t)。
	3. 自定义函数:
		NotNil()			// 是否为空
		GetValue()			// 获取值
		GetQueryNilStr()	// 查询操作字段是 NULL 时能用。
------ */

// LocalStr 自定义字符串。 binding:"required" 时, 前端传 ""、null 会触发检测。。。
type LocalStr string

// UnmarshalJSON 解码
func (t *LocalStr) UnmarshalJSON(b []byte) error {
	fmt.Println(b, string(b), TypeOf(string(b))) // 传 null 时: [110 117 108 108] null string; 传字符串时: [34 99 34] "c" string
	// m := make(map[string]interface{}) // 如果前端传的参数为 null。b 大概长这样 [110 117 108 108], 解码出来的 map 为 map[]
	// err := json.Unmarshal(b, &m)      // 如果参数不为 null。 err 这样 json: cannot unmarshal string into Go value of type map[string]interface {} map[]
	str := strings.Trim(string(b), "\"") // 剔除首未 "
	if str == "null" {                   // json 解码时, 前端传入 null, 是字符串, 所以这里判断是否为 "null"。。。
		str = ""
	}
	*t = LocalStr(str)
	return nil
}

// MarshalJSON 编码
func (t LocalStr) MarshalJSON() ([]byte, error) {
	var b []byte
	var err error
	if string(t) == "" { // LocalStr 默认值是 ""。
		b, err = json.Marshal(nil)
	} else {
		b, err = json.Marshal(string(t))
	}
	return b, err
}

// Value 保存到数据库时调用。会调用两次, 原因未知。
func (t LocalStr) Value() (driver.Value, error) {
	if string(t) == "" {
		return nil, nil
	}
	return string(t), nil
}

// Scan 接受数据库数据时调用。数据库中为 NULL 时, 不会调用 Scan 函数。。。。
func (t *LocalStr) Scan(v interface{}) error {
	value, ok := v.([]byte)
	if ok {
		*t = LocalStr(value)
	} else {
		*t = ""
	}
	return nil
}

// NotNil 判断不为空。LocalStr "null", "" 都是空, 返回 false 。
func (t LocalStr) NotNil() bool {
	if string(t) == "" {
		return false
	}
	return true
}

// GetValue 获取值。 "" 会返回 nil
func (t LocalStr) GetValue() interface{} {
	if string(t) == "" {
		return nil
	}
	return string(t)
}

// GetQueryNilStr 获取 query 条件
func (t LocalStr) GetQueryNilStr(column string) string {
	if string(t) == "" {
		return column + " is NULL"
	}
	return fmt.Sprintf(column+" = '%s'", t)
}
